﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using SdlDotNet.Input;
using SdlDotNet.Graphics;
using MonoPhysics;

namespace Monophysics_Demo
{
    partial class Demo
    {
        private List<Point> pointList;
        public static List<BoardPolygon> poly;
        private bool enregistrement;
        private bool stock;
        private bool showForces;
        private bool showAABB;
        private bool convexOnly;
        private BoardPolygon draging;
        private Vector dragPoint;
        private MonoPhysics.MonoPhysics PhysicEngine;
        private BoardPolygon Selected = null;
        private float TimeStep = 0;
        private int PhysT = 0;
        private float RestitutionCoeff = 0;
        private bool printCircles = true;
        public static bool AA = false;

        static void Main(string[] args)
        {
            Demo p = new Demo();
            p.Go();
        }

        public Demo()
        {
            this.ccph = new Color[1000];
            Random r = new Random();
            for (int i = 0; i < 1000; i++)
            {
                ccph[i] = Color.FromArgb(r.Next(0, 255), r.Next(0, 255), r.Next(0, 255));
            }
            this.enregistrement = false;
            this.stock = false;
            this.showAABB = false;
            this.showForces = false;
            this.convexOnly = false;
            this.PhysicEngine = new MonoPhysics.MonoPhysics();
            this.pointList = new List<Point>();
            Demo.poly = new List<BoardPolygon>();

            Video.Initialize();
            Video.Initialize();
            Video.WindowCaption = "MonoPhysics_Demo";
            Video.SetVideoMode(1000, 800, 32, true, false, false, true, true);

            InitDemo();
        }

        private void InitDemo()
        {
            // On ajoute le sol:
            List<PointD> pts = new List<PointD>();
            pts.Add(new PointD(300, 0));
            pts.Add(new PointD(0, 100));
            pts.Add(new PointD(799, 100));
            pts.Add(new PointD(799, 0));
            //BoardPolygon bp = new BoardPolygon(new Vector(850, 549, 0), 0, pts, 0, true, 0);
            //Demo.poly.Add(bp);

            //this.PhysicEngine.AddRigidBody(bp);
            this.PhysicEngine.Active = true;
        }


        public void Go()
        {
            SdlDotNet.Input.Keyboard.UnicodeEnabled = true;
            SdlDotNet.Core.Events.Tick += new EventHandler<SdlDotNet.Core.TickEventArgs>(Events_Tick);
            SdlDotNet.Core.Events.MouseMotion += new EventHandler<SdlDotNet.Input.MouseMotionEventArgs>(InterpretEvent);
            SdlDotNet.Core.Events.MouseButtonDown += new EventHandler<SdlDotNet.Input.MouseButtonEventArgs>(InterpretEvent);
            SdlDotNet.Core.Events.MouseButtonUp += new EventHandler<SdlDotNet.Input.MouseButtonEventArgs>(InterpretEvent);
            SdlDotNet.Core.Events.Quit += new EventHandler<SdlDotNet.Core.QuitEventArgs>(Events_Quit);
            SdlDotNet.Core.Events.VideoResize += new EventHandler<VideoResizeEventArgs>(Events_VideoResize);
            SdlDotNet.Core.Events.KeyboardDown += new EventHandler<KeyboardEventArgs>(Events_KeyboardDown);
            SdlDotNet.Core.Events.KeyboardUp += new EventHandler<KeyboardEventArgs>(Events_KeyboardUp);
            SdlDotNet.Core.Events.Run();
        }

        void Events_KeyboardUp(object sender, KeyboardEventArgs e)
        {
            if (e.Key == Key.RightArrow)
            {
                if (Demo.poly.Count > 0)
                    this.PhysicEngine.TryMove(MonoPhysics.MonoPhysics.MouvementType.Passive, Demo.poly[Demo.poly.Count - 1], 0);
            }
            else if (e.Key == Key.LeftArrow)
            {
                if (Demo.poly.Count > 0)
                    this.PhysicEngine.TryMove(MonoPhysics.MonoPhysics.MouvementType.Passive, Demo.poly[Demo.poly.Count - 1], 0);
            }
        }

        void Events_KeyboardDown(object sender, KeyboardEventArgs e)
        {
            if (e.Key == Key.F1) // efface TOUT
            {
                foreach (BoardPolygon bp in Demo.poly)
                    this.PhysicEngine.RemoveRigidBody(bp);

                Demo.poly.Clear();
                InitDemo();
            }
            else if (e.Key == Key.F2) // efface le dernier element ajoute.
            {
                int i = Demo.poly.Count - 1;
                if (i <= -1) // il n'y a plus rien, on reinitilalise
                {
                    InitDemo();
                    return;
                }
                BoardPolygon last = Demo.poly[i];
                this.PhysicEngine.RemoveRigidBody(last);
                Demo.poly.RemoveAt(i);
            }
            else if (e.Key == Key.F3)
                this.showForces = !this.showForces;
            else if (e.Key == Key.F4)
                this.showAABB = !this.showAABB;
            else if (e.Key == Key.F5)
                this.convexOnly = !this.convexOnly;
            else if (e.Key == Key.RightArrow)
                this.PhysicEngine.TryMove(MonoPhysics.MonoPhysics.MouvementType.WalkRight, Demo.poly[Demo.poly.Count - 1], 20);
            else if (e.Key == Key.LeftArrow)
                this.PhysicEngine.TryMove(MonoPhysics.MonoPhysics.MouvementType.WalkLeft, Demo.poly[Demo.poly.Count - 1], -20);
            else if (e.Key == Key.Space)
                this.PhysicEngine.TryJump(MonoPhysics.MonoPhysics.MouvementType.WalkRight, Demo.poly[Demo.poly.Count - 1]);
            else if (e.Key == Key.F12)
                this.PhysicEngine.SweepAndPruneON = !this.PhysicEngine.SweepAndPruneON;
            else if (e.Key == Key.F11)
                this.PhysicEngine.CorrectionsUseMink = !this.PhysicEngine.CorrectionsUseMink;
            else if (e.Key == Key.F10)
                ImpulseSolver.AllowRotations = !ImpulseSolver.AllowRotations;
            else if (e.Key == Key.Zero)
                this.RestitutionCoeff = 0;
            else if (e.Key == Key.C)
                this.printCircles = !this.printCircles;
            else if (e.Key == Key.A)
                AA = !AA;
            else if (e.Key == Key.M)
                this.PhysicEngine.showCollisionMarks = !this.PhysicEngine.showCollisionMarks;
            else if (e.Key == Key.P)
                this.PhysicEngine.Active = !this.PhysicEngine.Active;
            else if (e.Key == Key.UpArrow)
                this.RestitutionCoeff = Math.Min(RestitutionCoeff + 0.1f, 1);
            else if (e.Key == Key.DownArrow)
                this.RestitutionCoeff = Math.Max(RestitutionCoeff - 0.1f, 0);
            else if (e.Key == Key.PageUp)
            {

                //GeometryHelper.H++;
                this.DisplayedTreeH = (this.DisplayedTreeH == null) ? this.DisplayedTreeH = 0 : this.DisplayedTreeH + 1;
            }
            else if (e.Key == Key.PageDown)
            {
                //GeometryHelper.H--;
                if (this.DisplayedTreeH != null)
                    this.DisplayedTreeH = (this.DisplayedTreeH == 0) ? this.DisplayedTreeH = null : this.DisplayedTreeH - 1;
            }

            else if (e.Key == Key.Delete && this.Selected != null)
            {
                this.PhysicEngine.RemoveRigidBody(this.Selected);
                Demo.poly.Remove(this.Selected);
                this.Selected = null;
            }
        }

        void Events_VideoResize(object sender, VideoResizeEventArgs e)
        {
            Video.SetVideoMode(e.Width, e.Height, 32, true, false, false, true, true);
        }

        void Events_Quit(object sender, SdlDotNet.Core.QuitEventArgs e)
        {
            SdlDotNet.Core.Events.QuitApplication();
        }

        void Events_Tick(object sender, SdlDotNet.Core.TickEventArgs e)
        {
            this.TimeStep = e.SecondsElapsed;
            int t1 = SdlDotNet.Core.Timer.TicksElapsed;
            PhysicEngine.UpdatePhysics(e.SecondsElapsed);
            this.PhysT = (SdlDotNet.Core.Timer.TicksElapsed - t1);
            Video.Screen.Fill(Color.Black);
            foreach (BoardPolygon pl in Demo.poly)
                pl.Draw();
            if (this.Selected != null)
            {
                Point SelPos = new Point((int)this.Selected.Pos.X, (int)this.Selected.Pos.Y);
                Video.Screen.Draw(new SdlDotNet.Graphics.Primitives.Circle(SelPos, 11), Color.White, true, true);
                Video.Screen.Draw(new SdlDotNet.Graphics.Primitives.Circle(SelPos, 19), Color.White, true, false);
                Video.Screen.Draw(new SdlDotNet.Graphics.Primitives.Circle(SelPos, 29), Color.White, true, false);
            }
            foreach (Point pt in this.pointList)
            {
                SdlDotNet.Graphics.Primitives.Circle c = new SdlDotNet.Graphics.Primitives.Circle(pt, 1);
                Video.Screen.Draw(c, Color.White, true, false);
            }
            foreach (BoardPolygon pl in Demo.poly)
            {
                int nbrf = pl.PhysicStats.Forces.Count;
                foreach (Force f in pl.PhysicStats.Forces)
                {
                    if (this.showForces)
                        DrawForce(f, pl.Pos, pl.C, nbrf * 2);
                    if (this.showAABB)
                        DrawAABB(pl.ShapePosDim, pl.C);
                }
            }
            UpdateAndDrawDraggingForce();
            //Console.WriteLine(MathGeometryHelper.DistPtDrt(new PointD(Video.Screen.Width, 0), new PointD(0, Video.Screen.Height), new PointD(Mouse.MousePosition.X, Mouse.MousePosition.Y)));
            //Video.Screen.Draw(new SdlDotNet.Graphics.Primitives.Line(new Point(Video.Screen.Width, 0), new Point(0, Video.Screen.Height)), Color.AliceBlue);
            DrawEnvDatas();
            DrawsphereTrees();
            Video.Update();
        }





        #region Evenements souris
        public void InterpretEvent(object sender, EventArgs e)
        {
            int l = pointList.Count;
            if (e is MouseButtonEventArgs)
            {
                Point mpos = ((MouseButtonEventArgs)e).Position;
                if ((((MouseButtonEventArgs)e).Button == MouseButton.PrimaryButton || ((MouseButtonEventArgs)e).Button == MouseButton.SecondaryButton))
                {
                    if (((MouseButtonEventArgs)e).ButtonPressed)
                    {
                        if (l < 2 || l >= 2 && mpos != pointList[l - 1] && mpos != pointList[l - 2]) // trois points consecutifs ne doivent pas etre au meme endroit!
                            pointList.Add(new Point(mpos.X, mpos.Y));
                        enregistrement = true;
                    }
                    else
                    {
                        enregistrement = false;
                        if (pointList.Count > 2)
                        {
                            System.Collections.ArrayList aList = /*(this.convexOnly) ? GeometryHelper.ConveXhull(this.pointList) : */new System.Collections.ArrayList(this.pointList);
                            List<Point> pts = new List<Point>(aList.Cast<Point>());
                            List<PointD> ps = new List<PointD>();
                            RectangleF posd = GeometryHelper.GetMinimalRect(pts);
                            int le = pts.Count;
                            for (int i = 0; i < le; i++)
                            {
                                Point p = pts[i];
                                ps.Add(new PointD((p.X), (p.Y)));
                            }
                            if (ps.Count > 3)
                            {
                                float mass = (((MouseButtonEventArgs)e).Button == MouseButton.PrimaryButton) ? 0.0005f : 0;
                                float inert = (((MouseButtonEventArgs)e).Button == MouseButton.PrimaryButton) ? 0.0005f : 0;
                                BoardPolygon poly = new BoardPolygon(new Vector(mpos), mass, ps, inert, !(((MouseButtonEventArgs)e).Button == MouseButton.PrimaryButton), this.RestitutionCoeff);
                                Demo.poly.Add(poly);

                                this.PhysicEngine.AddRigidBody(poly);
                            }
                        }
                    }
                    pointList.Clear();
                }
                else if (((MouseButtonEventArgs)e).Button == MouseButton.MiddleButton)
                {
                    if (((MouseButtonEventArgs)e).ButtonPressed)
                    {
                        foreach (BoardPolygon bp in Demo.poly)
                        {
                            if (bp.ShapePosDim.Contains(((MouseButtonEventArgs)e).Position))
                            {
                                this.draging = bp;
                                this.Selected = bp;
                                bp.HangPoint = new Vector(((MouseButtonEventArgs)e).Position) - this.draging.Pos;
                                break;
                            }
                            this.Selected = null;
                        }
                    }
                    else
                    {
                        if (this.draging != null)
                        {
                            PhysicContext pc = this.draging.PhysicStats;
                            pc.PersistantForce = new Force(new Vector(), new Vector());
                            this.draging.PhysicStats = pc;
                            this.draging = null;
                        }
                    }
                }
            }
            else
                if (e is MouseMotionEventArgs)
                {
                    Point mpos = ((MouseMotionEventArgs)e).Position;
                    if (enregistrement)
                    {
                        if (stock)
                        {
                            if (l < 2 || l >= 2 && (mpos.Y != pointList[l - 1].Y || mpos.Y != pointList[l - 1].Y) && (mpos.X != pointList[l - 1].X || mpos.X != pointList[l - 1].X)) // trois points consecutifs ne doivent pas etre au meme endroit!
                                pointList.Add(new Point(mpos.X, mpos.Y));
                        }
                        stock = !stock;
                    }
                }
        }
        #endregion
    }
}
